from PyQt5.QtWidgets import QWidget, QVBoxLayout, QScrollArea, QLabel
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
import fitz  # PyMuPDF
import logging

class PDFViewer(QWidget):
    # 添加信号
    pdf_loaded = pyqtSignal(bool, int)  # 包含总页数的信号
    page_changed = pyqtSignal(int)  # 页码变更信号
    
    def __init__(self):
        super().__init__()
        self.current_page = 0
        self.doc = None
        self.zoom_factor = 1.0
        self.rotation = 0
        self.total_pages = 0
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout(self)
        
        # 创建滚动区域
        self.scroll_area = QScrollArea(self)
        self.scroll_area.setWidgetResizable(True)
        
        # 创建显示标签
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        self.scroll_area.setWidget(self.image_label)
        
        # 添加主要组件到布局
        self.layout.addWidget(self.scroll_area)

    def load_pdf(self, file_path):
        try:
            self.doc = fitz.open(file_path)
            self.total_pages = len(self.doc)
            self.current_page = 0  # 从第一页开始，索引为0
            
            # 发出PDF加载成功信号，包含总页数
            self.pdf_loaded.emit(True, self.total_pages)
            
            # 确保页面渲染成功后才发送页码变更信号
            self.render_page()
        except Exception as e:
            logging.error(f"PDF加载错误: {str(e)}")
            self.pdf_loaded.emit(False, 0)

    def render_page(self):
        """渲染当前PDF页面
        将PDF页面转换为图片并显示在界面上，支持缩放和旋转
        """
        if not self.doc:
            return
            
        # 获取当前页面对象
        page = self.doc[self.current_page]
        # 创建缩放矩阵，设置缩放因子
        zoom_matrix = fitz.Matrix(self.zoom_factor, self.zoom_factor)
        # 如果有旋转角度，应用旋转变换
        if self.rotation:
            zoom_matrix.preRotate(self.rotation)
            
        # 获取页面的像素图，应用变换矩阵
        pix = page.get_pixmap(matrix=zoom_matrix)
        # 设置图像格式为RGB888
        fmt = QImage.Format_RGB888

        # 从像素数据创建QImage对象
        img = QImage(pix.samples,  # 像素数据
                    pix.width,     # 图像宽度
                    pix.height,    # 图像高度
                    pix.stride,    # 每行字节数
                    fmt)          # 图像格式
        # 将QImage转换为QPixmap用于显示
        pixmap = QPixmap.fromImage(img)
        # 在标签中显示图像
        self.image_label.setPixmap(pixmap)
        
        # 渲染完成后发出页码变更信号
        # 这里确保页码从1开始，符合用户习惯
        if self.doc:
            current_page_number = self.current_page + 1  # 转换为从1开始的页码
            self.page_changed.emit(current_page_number)

    def rotate_current_page(self, angle):
        """旋转当前页面
        Args:
            angle: 旋转角度(顺时针，单位：度)
        """
        # 更新总旋转角度，保证在0-359度之间
        self.rotation = (self.rotation + angle) % 360
        # 重新渲染页面
        self.render_page()

    def zoom_in(self):
        """放大当前页面
        放大比例为1.2倍
        """
        self.zoom_factor *= 1.2
        self.render_page()

    def zoom_out(self):
        self.zoom_factor /= 1.2
        self.render_page()

    def next_page(self):
        if self.doc and self.current_page < self.total_pages - 1:
            self.current_page += 1
            self.render_page()

    def prev_page(self):
        if self.doc and self.current_page > 0:
            self.current_page -= 1
            self.render_page()

    def goto_page(self, page_num):
        """转到指定页码
        
        Args:
            page_num: 页码(从1开始)
        """
        if self.doc and 1 <= page_num <= self.total_pages:
            self.current_page = page_num - 1
            self.render_page()

    def fit_to_page(self):
        if not self.doc or not self.current_page < self.doc.page_count:
            return
            
        view_width = self.scroll_area.width() - 20  # 留出滚动条空间
        view_height = self.scroll_area.height() - 20
        
        page = self.doc[self.current_page]
        page_width = page.rect.width
        page_height = page.rect.height
        
        width_ratio = view_width / page_width
        height_ratio = view_height / page_height
        self.zoom_factor = min(width_ratio, height_ratio)
        self.render_page()
        
    def fit_to_width(self):
        if not self.doc or not self.current_page < self.doc.page_count:
            return
            
        view_width = self.scroll_area.width() - 20  # 留出滚动条空间
        page = self.doc[self.current_page]
        self.zoom_factor = view_width / page.rect.width
        self.render_page()

    def close_document(self):
        """关闭当前打开的PDF文档"""
        if self.doc:
            self.doc.close()
            self.doc = None
            self.current_page = 0
            self.total_pages = 0
            self.zoom_factor = 1.0
            self.rotation = 0
            self.image_label.clear()
            
            # 发出PDF关闭的信号
            self.pdf_loaded.emit(False, 0)
